﻿/*
Copyright © 2011 François Karman

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

See <license.txt> for the complete license of the software.
*/

using System;
using System.Collections;
using System.Collections.Generic;

namespace Simple.Storage
{
    /// <summary>
    /// Provides a read-only layer around an existing dictionary.
    /// </summary>
    /// <typeparam name="TKey">
    /// The type of keys in the dictionary.
    /// </typeparam>
    /// <typeparam name="TValue">
    /// The type of values in the dictionary.
    /// </typeparam>
    public class ReadOnlyDictionary<TKey, TValue>
        : ReadOnlyCollection<KeyValuePair<TKey, TValue>>, IDictionary<TKey, TValue>
    {
        /// <summary>
        /// The encapsulated dictionary.
        /// </summary>
        private readonly IDictionary<TKey, TValue> encapsulated;

        /// <summary>
        /// Initializes a new instance of the ReadOnlyDictionary class.
        /// </summary>
        /// <param name="encapsulated">The encapsulated dictionary.</param>
        /// <exception cref="ArgumentNullException">
        /// The <paramref name="encapsulated"/> parameter is <c>null</c>.
        /// </exception>
        public ReadOnlyDictionary(IDictionary<TKey, TValue> encapsulated)
            : base(encapsulated)
        {
            // No null check: done by base constructor
            this.encapsulated = encapsulated;
        }

        /// <summary>
        /// Gets a collection containing the keys of the dictionary.
        /// </summary>
        public ICollection<TKey> Keys
        {
            get { return this.encapsulated.Keys; }
        }

        /// <summary>
        /// Gets a collection containing the values of the dictionary.
        /// </summary>
        public ICollection<TValue> Values
        {
            get { return this.encapsulated.Values; }
        }

        /// <summary>
        /// Gets or sets the element with the specified key.
        /// </summary>
        /// <param name="key">The key of the element to get or set.</param>
        /// <returns>The element with the specified key.</returns>
        public TValue this[TKey key]
        {
            get
            {
                return this.encapsulated[key];
            }

            set
            {
                throw new NotSupportedException();
            }
        }

        /// <summary>
        /// Determines whether the dictonary contains an element with the specified key.
        /// </summary>
        /// <param name="key">The key to locate in the dictionary.</param>
        /// <returns>
        /// <c>true</c> if the dictionary contains an element with the key;
        /// otherwise, <c>false</c>.
        /// </returns>
        public bool ContainsKey(TKey key)
        {
            return this.encapsulated.ContainsKey(key);
        }

        /// <summary>
        /// Gets the value associated with the specified key.
        /// </summary>
        /// <param name="key">The key whose value to get.</param>
        /// <param name="value">
        /// When this method returns, the value associated with the specified key, if
        /// the key is found; otherwise, the default value for the type of the value
        /// parameter. This parameter is passed uninitialized.
        /// </param>
        /// <returns>
        /// <c>true</c> if the dictionary contains an element with the specified key;
        /// otherwise, <c>false</c>.
        /// </returns>
        public bool TryGetValue(TKey key, out TValue value)
        {
            return this.encapsulated.TryGetValue(key, out value);
        }

        /// <summary>
        /// Adds an element with the provided key and value to the dictionary
        /// - always raises <see cref="NotSupportedException"/>.
        /// </summary>
        /// <param name="key">The object to use as the key of the element to add.</param>
        /// <param name="value">The object to use as the value of the element to add.</param>
        /// <exception cref="NotSupportedException">
        /// The dictionary is read-only.
        /// </exception>
        public void Add(TKey key, TValue value)
        {
            throw new NotSupportedException();
        }

        /// <summary>
        /// Removes the element with the specified key from the dictionary
        /// - always raises <see cref="NotSupportedException"/>.
        /// </summary>
        /// <param name="key">The key of the element to remove.</param>
        /// <returns>Always raises <see cref="NotSupportedException"/>.</returns>
        /// <exception cref="NotSupportedException">
        /// The dictionary is read-only.
        /// </exception>
        public bool Remove(TKey key)
        {
            throw new NotSupportedException();
        }
    }
}
